//
//  BaseModel.swift
//  WBSwift
//
//  Created by 贺瑞 on 2017/8/3.
//  Copyright © 2017年 herui. All rights reserved.
//

import UIKit

class BaseModel: NSObject, NSCoding {

    //dict转model时防止崩溃
    override func setValue(_ value: Any?, forUndefinedKey key: String) { }
    
    
    required override init() {
        super.init()
    }
    init(keyvalues : [String : Any]) {
        super.init()
        setValuesForKeys(keyvalues)
    }

    
    //Unarchiver
    required init(coder aDecoder: NSCoder){
        super.init()
        
        let propertyList = getPropertyNameList()
        for propertyName in propertyList {
            if let val = aDecoder.decodeObject(forKey: propertyName) {
                setValue(val, forKey: propertyName)
            }
        }
    }
    //Archiver
    func encode(with aCoder: NSCoder) {
        let propertyList = self.getPropertyNameList()
        for propertyName in propertyList {
            aCoder.encode(value(forKey: propertyName), forKey: propertyName)
        }
    }
    
    //方便print打印
    override var description: String {
        var dictM = [String : Any]()
        let propertyList = self.getPropertyNameList()
        for propertyName in propertyList {
            dictM[propertyName] = value(forKey: propertyName)
        }
        return dictM.description
    }
}

extension BaseModel {
    
    func ClassInArray() -> [String : AnyClass] {
        return [String : AnyClass]()
    }
    
    //T@\"_TtC7WBSwift8UserInfo\",N,&,Vuser
    func getClassNameFromAttributes(attributes : String?) -> String? {
        
        guard let attr = attributes else {
            return nil
        }
        guard attr.hasPrefix("T@\"") else {
            return nil
        }

        
        let namespace = Bundle.main.infoDictionary?["CFBundleExecutable"] as! String

        guard let temp = attr.components(separatedBy: namespace).last else {
            return nil
        }

        let str = (temp as NSString)
        let index = str.range(of: "\"").location
        if index > 0 && str.length > 1 {
            var temp = str.substring(to: index)
            
            let pattern = "\\d*"
            let regex = try! NSRegularExpression(pattern: pattern, options: NSRegularExpression.Options(rawValue:0))
            let res = regex.matches(in: temp, options: NSRegularExpression.MatchingOptions(rawValue:0), range: NSMakeRange(0, temp.characters.count))
            
            return (temp as NSString).substring(from: res.first?.range.length ?? 0)
        }

        return nil
    }
    
    override func setValuesForKeys(_ keyedValues: [String : Any]) {
        super.setValuesForKeys(keyedValues)
        
        let propertyList = getPropertyList()
        let namespace = Bundle.main.infoDictionary?["CFBundleExecutable"] as! String
        
        for name in propertyList.keys {
            
            //从attr中找出UserInfo并创建对象，实现多层级dict->model
            //attr: T@\"_TtC7WBSwift8UserInfo\",N,&,Vuser
            guard let attr = propertyList[name] else {
                continue
            }
            guard attr.hasPrefix("T@\"") else {
                continue
            }
            guard let temp = attr.components(separatedBy: namespace).last else {
                continue
            }
            

            // 处理类型为[BaseModel]的情形
            if(attr.hasPrefix("T@\"NSArray\"")){
                
                guard let keyvaluesArray = keyedValues[name] as? [[String : Any]] else {
                    continue
                }

                
                let dict = ClassInArray()
                
                guard let cls = dict[name] else {
                    continue
                }
                var arr = [AnyObject]()
                for keyvalues in keyvaluesArray {
                    
                    guard let obj = NSObject.objFormClass(cls: cls) else {
                        continue
                    }
                    obj.setValuesForKeys(keyvalues)
                    arr.append(obj)
                }
                self.setValue(arr, forKey: name)
                continue
            }
            
            // 处理类型为BaseModel的情形
            guard let keyvalues = keyedValues[name] as? [String : Any] else {
                continue
            }

            //
            var str = (temp as NSString)
            let index = str.range(of: "\"").location
            if index > 0 && str.length > 1 {
                var temp = str.substring(to: index)
                
                
                let pattern = "\\d*"
                let regex = try! NSRegularExpression(pattern: pattern, options: NSRegularExpression.Options(rawValue:0))
                let res = regex.matches(in: temp, options: NSRegularExpression.MatchingOptions(rawValue:0), range: NSMakeRange(0, temp.characters.count))
                
                str = temp as NSString
                str = str.substring(from: res.first?.range.length ?? 0) as NSString
            }
            
            
            guard let obj = NSObject.objFormClassString(str: str as String) else {
                continue
            }
            obj.setValuesForKeys(keyvalues)
            self.setValue(obj, forKey: name)
        }
        
    }

}

extension BaseModel {
    
    func getPropertyList() -> [String : String] {
        
        var dictM = [String:String]()

        let outCount = UnsafeMutablePointer<UInt32>.allocate(capacity: 0)
        
        guard let buff = class_copyPropertyList(object_getClass(self), outCount) else {
            return dictM
        }
        
        for i in 0 ..< Int(outCount[0]) {
            guard let attr = String.init(utf8String: property_getAttributes(buff[i])) else {
                continue
            }
            guard let name =  String.init(utf8String: property_getName(buff[i])) else {
                continue
            }
            dictM[name] = attr
        }
        return dictM
    }
    
    func getPropertyNameList() -> Array<String> {
        return Array(getPropertyList().keys)
    }
}
